//////////////////////////////////////////////////////
// 程序名称：3.2 实现多步复合变换，并显示动画效果
// 功 能：如上。可交互
// 编译环境：Visual Studio 2017，EasyX_20190219(beta)
// 作 者：xyqlx<mxxyqlx@qq.com>
// 最后修改：2019-4-7
#include <conio.h>
#include <graphics.h>
#include <cmath>
#include <cstring>
#include <vector>
#include <ctime>
#include <list>

const float feps = 1e-8f;
int sgn(float f) { return f < -feps ? -1 : (f < feps ? 0 : 1); }

class Vector2
{
  public:
	float mat[3];
	Vector2() : Vector2(0.0f, 0.0f) {}
	Vector2(float x, float y, float w = 1.0f)
	{
		mat[0] = x;
		mat[1] = y;
		mat[2] = w;
	}
	Vector2(const Vector2& rhs){
		mat[0] = rhs.mat[0];
		mat[1] = rhs.mat[1];
		mat[2] = rhs.mat[2];
	}
	const Vector2& operator=(const Vector2& rhs){
		mat[0] = rhs.mat[0];
		mat[1] = rhs.mat[1];
		mat[2] = rhs.mat[2];
		return *this;
	}
	float Norm() const { return sqrt(mat[0] * mat[0] + mat[1] * mat[1]); }
	bool Normalize()
	{
		float r = Norm();
		if (sgn(r))
		{
			mat[0] /= r;
			mat[1] /= r;
			return 1;
		}
		return 0;
	}
};
Vector2 operator+(const Vector2 &lhs, const Vector2 &rhs)
{
	return Vector2(lhs.mat[0] + rhs.mat[0], lhs.mat[1] + rhs.mat[1], lhs.mat[2]);
}
Vector2 operator-(const Vector2 &lhs, const Vector2 &rhs)
{
	return Vector2(lhs.mat[0] - rhs.mat[0], lhs.mat[1] - rhs.mat[1], lhs.mat[2]);
}
Vector2 operator-(const Vector2 &rhs)
{
	return Vector2(-rhs.mat[0], -rhs.mat[1], rhs.mat[2]);
}
float Distance(const Vector2 &lhs, const Vector2 &rhs)
{
	return sqrt(pow(lhs.mat[0] - rhs.mat[0], 2) + pow(lhs.mat[1] - rhs.mat[1], 2));
}

class Transform2
{
  public:
	float mat[3][3];
	Transform2()
	{
		memset(mat, 0, sizeof(mat));
		mat[0][0] = mat[1][1] = mat[2][2] = 1.0f;
	}
	Transform2(const Transform2 &rhs)
	{
		memcpy(mat, rhs.mat, sizeof(mat));
	}
	Transform2 &operator=(const Transform2 &rhs)
	{
		memcpy(mat, rhs.mat, sizeof(mat));
	}
	const Transform2 &operator*=(const Transform2 &rhs)
	{
		float res[3][3];
		memset(res, 0, sizeof(res));
		for (int i = 0; i < 3; ++i)
		{
			for (int j = 0; j < 3; ++j)
			{
				for (int k = 0; k < 3; ++k)
				{
					res[i][j] += mat[i][k] * rhs.mat[k][j];
				}
			}
		}
		memcpy(mat, res, sizeof(mat));
		return *this;
	}
};
Transform2 operator*(const Transform2 &lhs, const Transform2 &rhs)
{
	Transform2 temp(lhs);
	temp *= rhs;
	return temp;
}
Transform2 TMultiply(const Transform2 &lhs, const Transform2 &rhs)
{
	return lhs * rhs;
}
Vector2 operator*(const Vector2 &lhs, const Transform2 &rhs)
{
	Vector2 res(0.0f, 0.0f, 0.0f);
	for (int i = 0; i < 3; ++i)
	{
		for (int j = 0; j < 3; ++j)
		{
			res.mat[i] += lhs.mat[j] * rhs.mat[j][i];
		}
	}
	return res;
}
Vector2 VMultiply(const Vector2 &lhs, const Transform2 &rhs)
{
	return lhs * rhs;
}
const Vector2 &operator*=(Vector2 &lhs, const Transform2 &rhs)
{
	float mat[3];
	memset(mat, 0, sizeof(mat));
	for (int i = 0; i < 3; ++i)
	{
		for (int j = 0; j < 3; ++j)
		{
			mat[i] += lhs.mat[j] * rhs.mat[j][i];
		}
	}
	memcpy(lhs.mat, mat, sizeof(mat));
	return lhs;
}
class Transform2Factory
{
  public:
	Transform2 Trivial()
	{
		Transform2 res;
		return res;
	}
	Transform2 Translation(const Vector2 &d)
	{
		Transform2 res;
		res.mat[2][0] = d.mat[0];
		res.mat[2][1] = d.mat[1];
		return res;
	}
	Transform2 Translation(float dx, float dy)
	{
		Transform2 res;
		res.mat[2][0] = dx;
		res.mat[2][1] = dy;
		return res;
	}
	Transform2 Rotation(Vector2 angle)
	{
		Transform2 res;
		if (angle.Normalize())
		{
			res.mat[0][0] = res.mat[1][1] = angle.mat[0];
			res.mat[0][1] = angle.mat[1];
			res.mat[1][0] = -angle.mat[1];
		}
		return res;
	}
	Transform2 Rotation(float angle)
	{
		Transform2 res;
		float c = cos(angle);
		float s = sin(angle);
		res.mat[0][0] = res.mat[1][1] = c;
		res.mat[0][1] = s;
		res.mat[1][0] = -s;
		return res;
	}
	Transform2 Scaling(const Vector2 &s)
	{
		Transform2 res;
		res.mat[0][0] = s.mat[0];
		res.mat[1][1] = s.mat[1];
		return res;
	}
	Transform2 Scaling(float sx, float sy)
	{
		Transform2 res;
		res.mat[0][0] = sx;
		res.mat[1][1] = sy;
		return res;
	}
	Transform2 SymmetryX()
	{
		Transform2 res;
		res.mat[1][1] = -1;
		return res;
	}
	Transform2 SymmetryY()
	{
		Transform2 res;
		res.mat[0][0] = -1;
		return res;
	}
	Transform2 Shear(float sx, float sy)
	{
		Transform2 res;
		res.mat[1][0] = sx;
		res.mat[0][1] = sy;
		return res;
	}
	Transform2 SymmetryLine(Vector2 v1, Vector2 v2)
	{
		Transform2 res;
		if (!sgn(v1.mat[0] - v2.mat[0]))
		{
			if (!sgn(v1.mat[1] - v2.mat[1]))
			{
				return res;
			}
			res *= Translation(-v1.mat[0], 0);
			res *= SymmetryY();
			res *= Translation(v1.mat[0], 0);
			return res;
		}
		else if (!sgn(v1.mat[1] - v2.mat[1]))
		{
			res *= Translation(0, -v1.mat[1]);
			res *= SymmetryX();
			res *= Translation(0, v1.mat[1]);
			return res;
		}
		res *= Translation(-v1);
		res *= Rotation((v2 - v1) * SymmetryX());
		res *= SymmetryX();
		res *= Rotation(v2 - v1);
		res *= Translation(v1);
		return res;
	}
};

//变换工厂
Transform2Factory factory;

class Shape
{
  public:
	Shape(int n) : stateNum(n) {}
	virtual void Redraw() const = 0;
	int stateNum;
	virtual void State(int &state, int x, int y) = 0;
	virtual const Shape &Multiply(const Transform2 &rhs) = 0;
	virtual ~Shape(){};
};

class Line : public Shape
{
  public:
	Vector2 v1, v2;
	COLORREF lineColor;
	Line() : Shape(4) {}
	Line(int x1, int y1, int x2, int y2, COLORREF lineColor = getlinecolor()) : Shape(4), v1(x1, y1), v2(x2, y2), lineColor(lineColor) {}
	virtual void Redraw() const
	{
		setlinecolor(lineColor);
		line(v1.mat[0], v1.mat[1], v2.mat[0], v2.mat[1]);
	}
	virtual void State(int &state, int x, int y)
	{
		switch (state)
		{
		case 1:
			v1.mat[0] = x;
			v1.mat[1] = y;
			break;
		case 2:
			v2.mat[0] = x;
			v2.mat[1] = y;
			lineColor = getlinecolor();
		case 3:
			line(v1.mat[0], v1.mat[1], v2.mat[0], v2.mat[1]);
			break;
		}
	}
	const Shape &Multiply(const Transform2 &rhs)
	{
		v1 *= rhs;
		v2 *= rhs;
		return *this;
	}
	virtual ~Line() {}
};
const Line &operator*=(Line &lhs, const Transform2 &rhs)
{
	lhs.v1 *= rhs;
	lhs.v2 *= rhs;
	return lhs;
}

class LineSet
{
  public:
	std::vector<Line> vec;
	LineSet() {}
	LineSet(const std::vector<int> &lines)
	{
		int n = lines.size() / 4;
		for (int i = 0; i < n; ++i)
		{
			vec.push_back(Line(lines[4 * i], lines[4 * i + 1], lines[4 * i + 2], lines[4 * i + 3]));
		}
	}
	LineSet(const LineSet &rhs)
	{
		vec = rhs.vec;
	}
	void SetColor(COLORREF color)
	{
		for (std::vector<Line>::iterator it = vec.begin(); it != vec.end(); ++it)
			it->lineColor = color;
	}
	void AddLine(const Line &rhs)
	{
		vec.push_back(rhs);
	}
	void Redraw() const
	{
		for (std::vector<Line>::const_iterator it = vec.begin(); it != vec.end(); ++it)
			it->Redraw();
	}
	const LineSet &operator*=(const Transform2 &rhs)
	{
		for (std::vector<Line>::iterator it = vec.begin(); it != vec.end(); ++it)
			it->Multiply(rhs);
		return *this;
	}
	LineSet operator*(const Transform2 &rhs) const
	{
		LineSet temp;
		temp.vec = vec;
		for (std::vector<Line>::iterator it = temp.vec.begin(); it != temp.vec.end(); ++it)
			it->Multiply(rhs);
		return temp;
	}
};

class Entity
{
  public:
	Vector2 center;
	Transform2 step;
	LineSet data;
	Entity(Vector2 center, Transform2 step, const LineSet &data) : center(center), step(step), data(data) {}
	void Redraw() const
	{
		(data * factory.Translation(center)).Redraw();
	}
	void Step()
	{
		center *= step;
	}
	const Entity &operator*=(const Transform2 &rhs)
	{
		data *= rhs;
		return *this;
	}
};

class Factory
{
  public:
	Vector2 center;
	Transform2 mach;
	LineSet appearance;
	Factory(Vector2 center, Transform2 mach, const LineSet &appearance) : center(center), mach(mach), appearance(appearance) {}
	bool isEntityIn(const Entity &rhs) const
	{
		return (center.mat[0] == rhs.center.mat[0] && abs(center.mat[1] - rhs.center.mat[1]) < 10);
	}
	void Process(Entity &rhs) const
	{
		if (isEntityIn(rhs))
		{
			rhs *= mach;
		}
	}
	void Redraw() const
	{
		(appearance * factory.Translation(center)).Redraw();
	}
};

void Display()
{
	//初始化转交变换与递增变换
	Transform2 handover = factory.Translation(100, -480);
	Transform2 step = factory.Translation(0, 10);
	//初始化图元图案
	std::vector<int> entityShape[10] = {{-3,-13,-3,4,-3,4,-11,4,-11,4,1,18,1,18,13,4,13,4,4,4,4,4,3,-15,3,-15,-3,-13}, {-8,-14,10,-14,10,-14,10,3,10,3,-4,3,-4,3,-4,12,-4,12,10,12,10,12,11,16,11,16,-9,16,-9,16,-9,-1,-9,-1,6,-1,6,-1,5,-11,5,-11,-8,-11,-8,-11,-8,-14}, {-2,14,4,5,4,5,18,5,18,5,18,-14,18,-14,-15,-14,-15,-14,-15,2,-15,2,-3,4,-3,4,-2,14}, {-4,-19,-4,-5,-4,-5,-18,12,-18,12,-18,16,-18,16,20,16,20,16,20,10,20,10,4,-5,4,-5,4,-19,4,-19,-4,-19}, {-16,-8,-8,-5,-8,-5,-11,1,-11,1,-10,5,-10,5,-9,11,-9,11,-1,12,-1,12,6,12,6,12,17,14,17,14,7,22,7,22,8,13,8,13,11,6,11,6,12,-1,12,-1,9,-8,9,-8,8,-12,8,-12,1,-13,1,-13,-4,-10,-4,-10,-8,-7,-8,-7,-9,-17,-9,-17,-16,-8}, {-12,-8,-1,0,-1,0,2,-4,2,-4,23,14,23,14,7,12,7,12,-2,6,-2,6,-4,5,-4,5,0,-1,0,-1,3,-4,3,-4,-10,-15,-10,-15,-12,-8}, {-5,-27,-14,-7,-14,-7,-14,-5,-14,-5,-14,-1,-14,-1,-13,4,-13,4,-9,5,-9,5,-4,8,-4,8,2,10,2,10,5,10,5,10,10,10,10,10,13,8,13,8,15,6,15,6,17,-3,17,-3,14,-11,14,-11,-5,-27}, {-8,3,-17,5,-17,5,-19,-2,-19,-2,-11,-8,-11,-8,-5,-4,-5,-4,-8,-10,-8,-10,-2,-17,-2,-17,4,-17,4,-17,8,-10,8,-10,5,-5,5,-5,16,-6,16,-6,20,0,20,0,17,7,17,7,5,3,5,3,9,6,9,6,12,12,12,12,4,17,4,17,0,10,0,10,-2,16,-2,16,-11,12,-11,12,-8,3}, {0,-21,-16,-6,-16,-6,-16,11,-16,11,-6,10,-6,10,-6,-3,-6,-3,7,-4,7,-4,7,10,7,10,18,9,18,9,18,-4,18,-4,0,-21}, {-13,19,19,-7,19,-7,-19,-7,-19,-7,12,19,12,19,2,-21,2,-21,-13,19}};
	LineSet *entityLineSet[10];
	for (int i = 0; i < 10; ++i)
	{
		entityLineSet[i] = new LineSet(entityShape[i]);
	}
	//初始化工厂图案
	std::vector<int> factoryShape = {-48, 0, 48, 0, 48, 0, 48, 61, 48, 61, -48, 61, -48, 61, -48, 0};
	LineSet factoryLineSet(factoryShape);
	//初始化工厂
	float PI = 2.0f * acos(0.0f);
	const int tranNum = 9;
	Transform2 trans[tranNum] = {factory.Rotation(-PI * 137.5f / 180.0f), factory.SymmetryX(), factory.SymmetryY(),
						   factory.Scaling(1.5f, 1.0f), factory.Scaling(1.0f, 1.5f), factory.Shear(1.0f, 0.0f),
						   factory.Shear(0.0f, 1.0f),factory.Rotation(PI * 137.5f / 180.0f),factory.Shear(0.0f,0.5f)*factory.Scaling(1.0f,0.5f)};
	COLORREF tranColor[tranNum] = {MAGENTA, YELLOW, GREEN, CYAN, BLUE, BLACK, BROWN, LIGHTMAGENTA, LIGHTGRAY};
	const int factoryNum = 6;
	Factory *pFactory[factoryNum];
	int factoryType[factoryNum];
	for (int i = 0; i < factoryNum; ++i)
	{
		factoryType[i] = i;
		pFactory[i] = new Factory(Vector2(60 + i * 100, 210), trans[i], factoryLineSet);
		pFactory[i]->appearance.SetColor(tranColor[i]);
	}
	//准备绘图
	clock_t lastTime = clock(), currentTime;
	double interval_seconds = 0.1;
	IMAGE img(640, 480);
	std::list<Entity> entityList;
	SetWorkingImage(&img);
	setbkcolor(WHITE);
	cleardevice();
	int cnt = 0;
	int entityLineSetIndex = 0;
	MOUSEMSG msg;
	bool should_exit = 0;
	int col;
	//消息循环
	while (1)
	{
		currentTime = clock();
		if (currentTime - lastTime > interval_seconds * CLOCKS_PER_SEC)
		{
			lastTime = currentTime;
			if (cnt == 0)
			{
				entityList.push_back(Entity(Vector2(60, 0), step, *entityLineSet[entityLineSetIndex]));
				if (++entityLineSetIndex == 10)
					entityLineSetIndex = 0;
				cnt = 10;
			}
			SetWorkingImage(&img);
			setbkcolor(WHITE);
			cleardevice();
			for (std::list<Entity>::iterator it = entityList.begin(); it != entityList.end(); ++it)
			{
				for (int i = 0; i < factoryNum; ++i)
					pFactory[i]->Process(*it);
				it->Step();
				if (it->center.mat[1] >= 480)
					it->center *= handover;
				it->Redraw();
			}
			for (int i = 0; i < factoryNum; ++i)
			{
				pFactory[i]->Redraw();
			}
			if (entityList.front().center.mat[0] > 640)
				entityList.pop_front();
			SetWorkingImage();
			putimage(0, 0, &img, SRCCOPY);
			--cnt;
		}
		while(MouseHit()){
			msg = GetMouseMsg();
			//鼠标滚动条改变刷新速度
			if(msg.wheel < 0)
				interval_seconds *= 0.9;
			else if(msg.wheel > 0)
				interval_seconds *= 1.11;
			switch (msg.uMsg)
			{
				//左键改变对应列的变换形式
				case WM_LBUTTONDOWN:
					col = msg.x / 100;
					if(col < factoryNum)
					{
						factoryType[col] = (factoryType[col] + 1) % tranNum;
						pFactory[col] = new Factory(pFactory[col]->center,trans[factoryType[col]],factoryLineSet);
						pFactory[col]->appearance.SetColor(tranColor[factoryType[col]]);
					}
					break;
				//右键退出
				case WM_RBUTTONDOWN:
					should_exit = 1;
					break;
			}
		}
		if(should_exit)
			break;
	}
	//释放空间
	for (int i = 0; i < 10; ++i)
		delete entityLineSet[i];
	for (int i = 0; i < factoryNum; ++i)
		delete pFactory[i];
}

int main()
{
	// 创建绘图窗口，大小为 640x480 像素
	initgraph(640, 480);
	//填充背景为白色
	setbkcolor(WHITE);
	cleardevice();
	//开始绘制
	setlinecolor(RED);
	Display();
	//结束绘制
	closegraph(); // 关闭绘图窗口
	return 0;
}